home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 015 / bawk2a.arc / BAWK.C next >
Encoding:
C/C++ Source or Header  |  1986-07-25  |  11.5 KB  |  549 lines

  1. /*
  2.  * Bawk main program
  3.  */
  4. #define MAIN 1
  5.  
  6. #include <stdio.h>
  7.  
  8. #include "bawk.h"
  9.  
  10. /*
  11.  * Main program
  12.  */
  13. main( argc, argv )
  14. int argc;
  15. char **argv;
  16. {
  17.     void newfile();
  18.  
  19.     char gotrules, didfile, getstdin;
  20.  
  21.     getstdin =
  22.         didfile =
  23.         gotrules = 0;
  24.  
  25. /*
  26.  * Initialize global variables:
  27.  */
  28.     Beginact = (char *) NULL;
  29.     Endact = (char *) NULL;
  30.     Rules = (RULE *) NULL;
  31.     Rulep = (RULE *) NULL;
  32. #ifdef DEBUG
  33.     Debug = (char) NULL;
  34. #endif
  35.     Filename = (char *) NULL;
  36.     Linecount = 0;
  37.     Saw_break = (char) NULL;
  38.     Stackptr = Stackbtm - 1;
  39.     Stacktop = Stackbtm + MAXSTACKSZ;
  40.     Nextvar = Vartab;
  41.  
  42.     strcpy( Fieldsep, " \t" );
  43.     strcpy( Recordsep, "\n" );
  44.  
  45. /*
  46.  * Parse command line
  47.  */
  48.     while ( --argc ) {
  49.         if ( **(++argv) == '-' ) {
  50. /*
  51.  * Process dash options.
  52.  */
  53.             switch ( tolower( *(++(*argv)) ) ) {
  54. #ifdef DEBUG
  55.                  case 'd':
  56.                    ++Debug;
  57.                    break;
  58. #endif
  59.                case 0:
  60.                    ++getstdin;
  61.                    --argv;
  62.                    goto dosomething;
  63.                    break;
  64.                default:
  65.                    usage();
  66.                    }
  67.                }
  68.         else {
  69. dosomething:
  70.             if ( gotrules ) {
  71. /*
  72.  * Already read rules file - assume this is
  73.  * is a text file for processing.
  74.  */
  75.                 if ( ++didfile == 1 && Beginact ) doaction( Beginact );
  76.                 if ( getstdin ) {
  77.                     --getstdin;
  78.                     newfile( 0 );
  79.                     }
  80.                 else newfile( *argv );
  81.                 process();
  82.                 }
  83.             else {
  84. /*
  85.  * First file name argument on command line
  86.  * is assumed to be a rules file - attempt to
  87.  * compile it.
  88.  */
  89.                 if ( getstdin ) {
  90.                     --getstdin;
  91.                     newfile( 0 );
  92.                     }
  93.                 else newfile( *argv );
  94.                 compile();
  95.                 gotrules = 1;
  96.                 }
  97.             }
  98.         }
  99.     if ( !gotrules ) usage();
  100.     if ( ! didfile ) {
  101. /*
  102.  * Didn't process any files yet - process stdin.
  103.  */
  104.         newfile( 0 );
  105.         if ( Beginact ) doaction( Beginact );
  106.         process();
  107.         }
  108.     if ( Endact ) doaction( Endact );
  109.     }
  110.  
  111. /*
  112.  * Regular expression/action file compilation routines.
  113.  */
  114. compile() {
  115. /*
  116.  * Compile regular expressions and C actions into Rules struct,
  117.  * reading from current input file "Fileptr".
  118.  */
  119.     int c, len;
  120.  
  121. #ifdef DEBUG
  122.     if ( Debug ) error( "compiling...", 0 );
  123. #endif
  124.     while ( (c = getcharacter()) != -1 ) {
  125.         if ( c==' ' || c=='\t' || c=='\n' ) /* swallow whitespace */
  126.             ;
  127.         else if ( c=='#' ) {
  128. /*
  129.  * Swallow comments
  130.  */
  131.             while ( (c=getcharacter()) != -1 && c!='\n' ) 
  132.                 ;
  133.             }
  134.         else if ( c=='{' ) {
  135. #ifdef DEBUG
  136.             if ( Debug ) error( "action", 0 );
  137. #endif
  138. /*
  139.  * Compile (tokenize) the action string into our
  140.  * global work buffer, then allocate some memory
  141.  * for it and copy it over.
  142.  */
  143.             ungetcharacter( '{' );
  144.             len = act_compile( Workbuf );
  145.  
  146.             if ( Rulep && Rulep->action ) {
  147.                 Rulep->nextrule = (RULE *) getmem( sizeof( *Rulep ) );
  148.                 Rulep = Rulep->nextrule;
  149.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  150.                 }
  151.             if ( !Rulep ) {
  152. /*
  153.  * This is the first action encountered.
  154.  * Allocate the first Rules structure and
  155.  * initialize it
  156.  */
  157.                 Rules = Rulep = (RULE *) getmem( sizeof( *Rulep ) );
  158.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  159.                 }
  160.             Rulep->action = getmem( len );
  161.             movemem( Workbuf, Rulep->action, len );
  162.             }
  163.         else if ( c==',' ) {
  164. #ifdef DEBUG
  165.             if ( Debug ) error( "stop pattern", 0 );
  166. #endif
  167. /*
  168.  * It's (hopefully) the second part of a two-part
  169.  * pattern string.  Swallow the comma and start
  170.  * compiling an action string.
  171.  */
  172.             if ( !Rulep || !Rulep->pattern.start )
  173.                 error( "stop pattern without a start", RE_ERROR );
  174.             if ( Rulep->pattern.stop )
  175.                 error( "already have a stop pattern", RE_ERROR );
  176.             len = pat_compile( Workbuf );
  177.             Rulep->pattern.stop = getmem( len );
  178.             movemem( Workbuf, Rulep->pattern.stop, len );
  179.             }
  180.         else {
  181. /*
  182.  * Assume it's a regular expression pattern
  183.  */
  184. #ifdef DEBUG
  185.             if ( Debug ) error( "start pattern", 0 );
  186. #endif
  187.             ungetcharacter( c );
  188.             len = pat_compile( Workbuf );
  189.  
  190.             if ( *Workbuf == T_BEGIN ) {
  191. /*
  192.  * Saw a "BEGIN" keyword - compile following
  193.  * action into special "Beginact" buffer.
  194.  */
  195.                 len = act_compile( Workbuf );
  196.                 Beginact = getmem( len );
  197.                 movemem( Workbuf, Beginact, len );
  198.                 continue;
  199.                 }
  200.             if ( *Workbuf == T_END ) {
  201. /*
  202.  * Saw an "END" keyword - compile following
  203.  * action into special "Endact" buffer.
  204.  */
  205.                 len = act_compile( Workbuf );
  206.                 Endact = getmem( len );
  207.                 movemem( Workbuf, Endact, len );
  208.                 continue;
  209.                 }
  210.             if ( Rulep ) {
  211. /*
  212.  * Already saw a pattern/action - link in
  213.  * another Rules structure.
  214.  */
  215.                 Rulep->nextrule = (RULE *) getmem( sizeof( *Rulep ) );
  216.                 Rulep = Rulep->nextrule;
  217.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  218.                 }
  219.             if ( !Rulep ) {
  220. /*
  221.  * This is the first pattern encountered.
  222.  * Allocate the first Rules structure and
  223.  * initialize it
  224.  */
  225.                 Rules = Rulep = (RULE *) getmem( sizeof( *Rulep ) );
  226.                 fillmem( Rulep, sizeof( *Rulep ), 0 );
  227.                 }
  228.             if ( Rulep->pattern.start )
  229.                 error( "already have a start pattern", RE_ERROR );
  230.             Rulep->pattern.start = getmem( len );
  231.             movemem( Workbuf, Rulep->pattern.start, len );
  232.             }
  233.         }
  234.     endfile();
  235.     }
  236.  
  237. /*
  238.  * Text file main processing loop.
  239.  */
  240. process() {
  241. /*
  242.  * Read a line at a time from current input file at "Fileptr",
  243.  * then apply each rule in the Rules chain to the input line.
  244.  */
  245.     int i;
  246.  
  247. #ifdef DEBUG
  248.     if ( Debug ) error( "processing...", 0 );
  249. #endif
  250.     Recordcount = 0;
  251.     while ( getline() ) {
  252. /*
  253.  * Parse the input line.
  254.  */
  255.         Fieldcount = parse( Linebuf, Fields, Fieldsep );
  256. #ifdef DEBUG
  257.         if ( Debug>1 ) {
  258.             printf( "parsed %d words:\n", Fieldcount );
  259.             for(i=0; i<Fieldcount; ++i ) printf( "<%s>\n", Fields[i] );
  260.             }
  261. #endif
  262.         Rulep = Rules;
  263.         do {
  264.             if ( ! Rulep->pattern.start ) {
  265. /*
  266.  * No pattern given - perform action on
  267.  * every input line.
  268.  */
  269.                 doaction( Rulep->action );
  270.                 }
  271.             else if ( Rulep->pattern.startseen ) {
  272. /*
  273.  * Start pattern already found - perform
  274.  * action then check if line matches
  275.  * stop pattern.
  276.  */
  277.                 doaction( Rulep->action );
  278.                 if ( dopattern( Rulep->pattern.stop ) )
  279.                     Rulep->pattern.startseen = 0;
  280.                 }
  281.             else if ( dopattern( Rulep->pattern.start ) ) {
  282. /*
  283.  * Matched start pattern - perform action.
  284.  * If a stop pattern was given, set "start
  285.  * pattern seen" flag and process every input
  286.  * line until stop pattern found.
  287.  */
  288.                 doaction( Rulep->action );
  289.                 if ( Rulep->pattern.stop )
  290.                     Rulep->pattern.startseen = 1;
  291.                 }
  292.             }
  293.         while ( (Rulep = Rulep->nextrule) != 0 );
  294. /*
  295.  * Release memory allocated by parse().
  296.  */
  297.         while ( Fieldcount ) free( Fields[ --Fieldcount ] );
  298.         }
  299.     }
  300.  
  301. /*
  302.  * Miscellaneous functions
  303.  */
  304. parse( str, wrdlst, delim )
  305. char *str;
  306. char *wrdlst[];
  307. char *delim;
  308. {
  309. /*
  310.  * Parse the string of words in "str" into the word list at "wrdlst".
  311.  * A "word" is a sequence of characters delimited by one or more
  312.  * of the characters found in the string "delim".
  313.  * Returns the number of words parsed.
  314.  * CAUTION: the memory for the words in "wrdlst" is allocated
  315.  * by malloc() and should eventually be returned by free()...
  316.  */
  317.     int wrdcnt, wrdlen;
  318.     char wrdbuf[ MAXLINELEN ], c;
  319.  
  320.     wrdcnt = 0;
  321.     while ( *str ) {
  322.         while ( instr( *str, delim ) ) ++str;
  323.         if ( !*str ) break;
  324.         wrdlen = 0;
  325.         while ( ((c = *str) != 0) && !instr( c, delim ) ) {
  326.             wrdbuf[ wrdlen++ ] = c;
  327.             ++str;
  328.             }
  329.         wrdbuf[ wrdlen++ ] = 0;
  330. /*
  331.  * NOTE: allocate a MAXLINELEN sized buffer for every
  332.  * word, just in case user wants to copy a larger string
  333.  * into a field.
  334.  */
  335.         wrdlst[ wrdcnt ] = getmem( MAXLINELEN );
  336.         strcpy( wrdlst[ wrdcnt++ ], wrdbuf );
  337.         }
  338.     return wrdcnt;
  339.     }
  340.  
  341. unparse( wrdlst, wrdcnt, str, delim )
  342. char *wrdlst[];
  343. int wrdcnt;
  344. char *str;
  345. char *delim;
  346. {
  347. /*
  348.  * Replace all the words in "str" with the words in "wrdlst",
  349.  * maintaining the same word seperation distance as found in
  350.  * the string.
  351.  * A "word" is a sequence of characters delimited by one or more
  352.  * of the characters found in the string "delim".
  353.  */
  354.     int wc;
  355.     char strbuf[ MAXLINELEN ], *sp, *wp, *start;
  356.  
  357.     wc = 0; /* next word in "wrdlst" */
  358.     sp = strbuf; /* points to our local string */
  359.     start = str; /* save start address of "str" for later... */
  360.     while ( *str ) {
  361. /*
  362.  * Copy the field delimiters from the original string to
  363.  * our local version.
  364.  */
  365.         while ( instr( *str, delim ) ) *sp++ = *str++;
  366.         if ( !*str ) break;
  367. /*
  368.  * Skip over the field in the original string and...
  369.  */
  370.         while ( *str && !instr( *str, delim ) ) ++str;
  371.         if ( wc < wrdcnt ) {
  372. /*
  373.  * ...copy in the field in the wordlist instead.
  374.  */
  375.             wp = wrdlst[ wc++ ];
  376.             while ( *wp )
  377.                 *sp++ = *wp++;
  378.             }
  379.         }
  380. /*
  381.  * Tie off the local string, then copy it back to caller's string.
  382.  */
  383.     *sp = 0;
  384.     strcpy( start, strbuf );
  385.     }
  386.  
  387. instr( c, s )
  388. char c, *s;
  389. {
  390.     while ( *s ) if ( c==*s++ ) return 1;
  391.     return 0;
  392.     }
  393.  
  394. char *
  395. getmem( len )
  396. unsigned len;
  397. {
  398.     char *cp;
  399.  
  400.     if ( (cp = (char *) malloc( len )) != 0 ) return cp;
  401.     error( "out of memory", MEM_ERROR );
  402.     }
  403.  
  404. void
  405. newfile( s )
  406. char *s;
  407. {
  408.     Linecount = 0;
  409.     if ( (Filename = s) != 0 ) {
  410. #ifdef BDS_C
  411.         if ( fopen( s, Fileptr = Curfbuf ) == -1 )
  412. #else
  413.         if ( (Fileptr = fopen( s, "r" )) == 0)
  414. #endif
  415.            error( "file not found", FILE_ERROR );
  416.         }
  417.     else {
  418. /*
  419.  * No file name given - process standard input.
  420.  */
  421.         Fileptr = stdin;
  422.         Filename = "standard input";
  423.         }
  424.     }
  425.  
  426. getline() {
  427. /*
  428.  * Read a line of text from current input file.  Strip off
  429.  * trailing record seperator (newline).
  430.  */
  431.     int rtn, len;
  432.  
  433.     for ( len=0; len<MAXLINELEN; ++len ) {
  434.         if ( (rtn = getcharacter()) == *Recordsep || rtn == -1 ) break;
  435.         Linebuf[ len ] = rtn;
  436.         }
  437.     Linebuf[ len ] = 0;
  438.     if ( rtn == -1 ) {
  439.         endfile();
  440.         return 0;
  441.         }
  442.     return 1;
  443.     }
  444.  
  445. getcharacter() {
  446. /*
  447.  * Read a character from curren input file.
  448.  * WARNING: your getc() must convert lines that end with CR+LF
  449.  * to LF and CP/M's EOF character (^Z) to a -1.
  450.  * Also, getc() must return a -1 when attempting to read from
  451.  * an unopened file.
  452.  */
  453.     int c;
  454.  
  455. #ifdef BDS_C
  456. /*
  457.  * BDS C doesn't do CR+LF to LF and ^Z to -1 conversions <gag>
  458.  */
  459.     if ( (c = getc( Fileptr )) == '\r' ) {
  460.         if ( (c = getc( Fileptr )) != '\n' ) {
  461.             ungetc( c );
  462.             c = '\r';
  463.             }
  464.         }
  465.     else if ( c == 26 ) c = -1; /* ^Z */
  466. #else
  467.     c = getc( Fileptr );
  468. #endif
  469.     if ( c == *Recordsep ) ++Recordcount;
  470.     if ( c=='\n' ) ++Linecount;
  471.     return c;
  472.     }
  473.  
  474. ungetcharacter( c ) {
  475. /*
  476.  * Push a character back into the input stream.
  477.  * If the character is a record seperator, or a newline character,
  478.  * the record and line counters are adjusted appropriately.
  479.  */
  480.     if ( c == *Recordsep ) --Recordcount;
  481.     if ( c=='\n' ) --Linecount;
  482.     return ungetc( c, Fileptr );
  483.     }
  484.  
  485. endfile() {
  486.     fclose( Fileptr );
  487.     Filename = (char *) Linecount = 0;
  488.     }
  489.  
  490. error( s, severe )
  491. char *s;
  492. int severe;
  493. {
  494.     char *cp, *errat;
  495.  
  496.     if ( Filename ) fprintf( stderr, "%s:", Filename );
  497.     if ( Linecount ) fprintf( stderr, " line %d:", Linecount );
  498.     fprintf( stderr, " %s\n", s );
  499.     if ( severe ) exit( severe );
  500.     }
  501.  
  502. usage() {
  503.     error( "Usage: bawk <actfile> [<file> ...]\n", USAGE_ERROR );
  504.     }
  505.  
  506. movemem( from, to, count )
  507. char *from, *to;
  508. int count;
  509. {
  510.     while ( count-- > 0 ) *to++ = *from++;
  511.     }
  512.  
  513. fillmem( array, count, value )
  514. char *array, value;
  515. int count;
  516. {
  517.     while ( count-- > 0 ) *array++ = value;
  518.     }
  519.  
  520. strncmp( s, t, n )
  521. char *s, *t;
  522. int n;
  523. {
  524.     while ( --n>0 && *s && *t && *s==*t ) {
  525.         ++s;
  526.         ++t;
  527.         }
  528.     if ( *s || *t ) return *s - *t;
  529.     return 0;
  530.     }
  531.  
  532. num( c )
  533. char c;
  534. {
  535.     return '0'<=c && c<='9';
  536.     }
  537.  
  538. alpha( c )
  539. char c;
  540. {
  541.     return ('a'<=c && c<='z') || ('A'<=c && c<='Z') || c=='_';
  542.     }
  543.  
  544. alphanum( c )
  545. char c;
  546. {
  547.     return alpha( c ) || num( c );
  548.     }
  549.